#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <iostream>
#include <mili/mili.h>
#include "prot-filer/cached_reader.h"
#include "feca/feca.h"

using namespace std;
using namespace prot_filer;
using mili::insert_into;

class CompressedFilerTest: public ::testing::Test
{
protected:
    unsigned int size;
    virtual void SetUp()
    {
        size = 90;
        insert_into(data, AngleIdPair(3, 0));
        insert_into(data, AngleIdPair(3, 3));
        insert_into(data, AngleIdPair(3, 3));
        insert_into(data, AngleIdPair(3, 3));
        insert_into(data, AngleIdPair(2, 3));
        insert_into(data, AngleIdPair(1, 2));
    }

    virtual void TearDown()
    {
        AnglesReaderFactory::destroy_instance();
    }
    vector<AngleIdPair> data;
    void create(const string& file);
};

TEST_F(CompressedFilerTest, read)
{
    const string file = "test.xtc";
    create(file);
    AnglesReader* r = AnglesReaderFactory::get_instance()->create("compressed");
    AnglesData angles_data(data.size() + 1);
    unsigned int i = 0;
    r->open(file);
    while (!r->read(angles_data))
    {
        for (unsigned int c = 0; c < angles_data.nres - 1; ++c)
        {
            ASSERT_EQ(data[c].fi, angles_data.angles[c].fi);
            ASSERT_EQ(data[c].si, angles_data.angles[c].si);
        }
        ++i;
    }
    ASSERT_EQ(size, i);
    r->close();
    delete r;
    remove(file.c_str());
}

TEST_F(CompressedFilerTest, read_full_cache)
{
    const string file = "test.xtc";
    create(file);
    CachedReader<FullCache, AnglesReader, AnglesData> r(AnglesReaderFactory::get_instance()->create("compressed"));
    r.open(file);
    unsigned int i = 0;
    AnglesData* angles_data = NULL;
    while ((angles_data = r.read(i)) != NULL)
    {
        ASSERT_EQ(data.size(), angles_data->nres - 1);
        for (unsigned int c = 0; c < angles_data->nres - 1; ++c)
        {
            ASSERT_EQ(data[c].fi, angles_data->angles[c].fi);
            ASSERT_EQ(data[c].si, angles_data->angles[c].si);
        }
        ++i;
    }
    ASSERT_EQ(size, i);
    r.close();
    remove(file.c_str());
}

TEST_F(CompressedFilerTest, read_sliding)
{
    const string file = "test.xtc";
    create(file);
    CachedReader<SlidingWindowCache<2>::CacheType, AnglesReader, AnglesData> r(AnglesReaderFactory::get_instance()->create("compressed"));
    r.open(file);
    unsigned int i = 0;
    AnglesData* angles_data = NULL;
    while ((angles_data = r.read(i)) != NULL)
    {
        ASSERT_EQ(data.size(), angles_data->nres - 1);
        for (unsigned int c = 0; c < angles_data->nres - 1; ++c)
        {
            ASSERT_EQ(data[c].fi, angles_data->angles[c].fi);
            ASSERT_EQ(data[c].si, angles_data->angles[c].si);
        }
        ++i;
    }
    ASSERT_EQ(size, i);
    for (unsigned int c = 0; i < i; ++i)
    {
        angles_data = r.read(c);
        ASSERT_TRUE(angles_data != NULL);
    }
    r.close();
    remove(file.c_str());
}

void CompressedFilerTest::create(const string& file)
{
    AnglesMapping mapping(data.size() + 1);
    mapping.set_mapping(-60, -40);
    mapping.set_mapping(-60, 140);
    mapping.set_mapping(-130, 140);
    mapping.set_mapping(60, 30);

    AnglesData angles_data(data.size() + 1, &mapping);
    for (unsigned int i = 0; i < data.size(); ++i)
    {
        angles_data.angles[i].fi = data[i].fi;
        angles_data.angles[i].si = data[i].si;
    }
    CompressedWriter writer;
    writer.open(file);
    for (unsigned int i = 0; i < size; ++i)
    {
        writer.write(angles_data);
    }
    writer.close();
}
